home *** CD-ROM | disk | FTP | other *** search
- /////////////////////////////////////////////////////////////////
- // compoun.cpp: Compound number class implementation.
- // Copyright (c) 1992 Azarona Software. All rights reserved.
- // NOTE: Many of the routines here could be made inline for
- // significant performance gains.
- /////////////////////////////////////////////////////////////////
- #include <ctype.h>
- #include "compoun.h"
-
- Compound::Compound()
- // Default constructor sets number to "undefined."
- // Default Rational() constructor called implicitly
- : w(0)
- {
- // Nothing else to do
- }
-
- Compound::Compound(long n)
- // Converts whole number n into compound number <n 0/1>.
- : w(n), f(0)
- {
- // Nothing else to do
- }
-
- Compound::Compound(long n, Rational &r)
- // Constructors compound number <n r>.
- {
- Set(n, r);
- }
-
- Compound::Compound(Compound const &c)
- // Copy constructor
- : w(c.w), f(c.f)
- {
- // Nothing else to do
- }
-
- Compound &Compound::operator=(Compound const &c)
- // Overloaded assignment.
- {
- w = c.w; f = c.f; return *this;
- }
-
- void Compound::Simplify()
- // Simplifies the compound number.
- // ASSUMES fractional part is already simplified.
- {
- if (f.IsUndefined()) {
- w = 0; // So we have <0 0/0> for undefined
- }
- else {
- // Split f into whole number plus fraction.
- long w1 = f.RemoveWholePart();
- w += w1; // Add whole number from split to w.
- // If whole number and fraction have different signs,
- // we must force them to have same signs and simplify
- // further.
- if (w > 0 && f.IsNegative()) {
- // We're using the formula: w + f = (w-1) + (f+1).
- w--;
- f++;
- }
- else if (w < 0 && f.IsPositive()) {
- // We're using the formula: w + f = (w+1) + (f-1).
- w++;
- f--;
- }
- }
- }
-
- void Compound::Set(long n, Rational &r)
- {
- w = n; f = r;
- Simplify();
- }
-
- void Compound::Negate()
- // Take the negative of this compound number.
- {
- w = -w;
- f.Negate();
- }
-
- void Compound::Invert()
- // Divide 1 by this number, store result in this number.
- // Uses formula: 1/c = 1/(w + n/d) = d/(w*d + n).
- // Result is then simplified.
- // If number is zero, we'll get a result of <0 0/0>.
- // WARNING: Overflow is not checked!
- {
- Rational r(f.Denominator(), w*f.Denominator() + f.Numerator());
- operator=(Compound(0, r));
- }
-
- int Compound::IsUndefined() const
- {
- return f.IsUndefined();
- }
-
- int Compound::IsNegative() const
- {
- return w < 0 || (w == 0 && f.IsNegative());
- }
-
- int Compound::IsPositive() const
- {
- return w > 0 || (w == 0 && f.IsPositive());
- }
-
- int Compound::IsZero() const
- {
- return w == 0 && f.IsZero();
- }
-
-
- istream &operator>>(istream &s, Compound &cn)
- // Reads in a compound number. Legal syntaxes are:
- // w, <n/d>, and <w n/d>. Appropriate whitespace
- // is allowed. If the stream s is not in a good state upon
- // return, then cn will contain <0 0/0>.
- {
- char c, syntax_error = 0;
- long n, d;
-
- if (s >> c) { // Read in first non-whitespace character
- if (isdigit(c) || (c == '-') || (c == '+')) {
- // We have a whole number. Put back character
- // and then read in the whole number.
- s.putback(c);
- if (s >> cn.w) {
- cn.f = 0; // We have zero fractional part
- }
- }
- else if (c == '<') {
- // Reading in <w n/d> or <n/d> syntax
- if (s >> n) {
- // Might have w or n, find out by looking for '/'
- if (s >> c) {
- if (c == '/') {
- // Guess we have n. That means w = 0. Grab d.
- cn.w = 0;
- s >> d;
- }
- else { // We have w. Putback c, look for n/d.
- cn.w = n;
- s.putback(c);
- if (s >> n) { // We've got numerator
- if (s >> c) { // Look for '/'
- if (c == '/')
- s >> d;
- else syntax_error = 1;
- }
- }
- }
- if (s) { // Good so far, so look for '>'
- if (s >> c) {
- if (c == '>') { // Good read
- cn.f.Set(n, d);
- cn.Simplify();
- }
- else syntax_error = 1;
- }
- }
- }
- }
- }
- else syntax_error = 1;
- }
- if (syntax_error) s.clear(ios::failbit);
- if (!s) { // Stream failure, so result is undefined
- cn.w = 0; cn.f.Set(0, 0);
- }
- return s;
- }
-
- ostream &operator<<(ostream &s, const Compound &c)
- // Output compound number c to stream. Outputs "und"
- // for <0 0/0>. If fraction part is zero, it is not shown.
- {
- if (c.IsUndefined()) return s << "und";
- if (c.f.IsZero()) return s << c.w;
- s << '<';
- if (c.w != 0) s << c.w << ' ';
- s << c.f.Numerator() << '/' << c.f.Denominator();
- return s << '>';
- }
-
- Compound Compound::operator-() const
- // Unary - operator. Computes negative of this number
- // and returns a copy.
- {
- return Compound(-w, -f);
- }
-
- Compound Compound::operator+() const
- // Unary + operator. Returns a copy of this number.
- // (Thus, semantics are consistent with unary -).
- {
- return Compound(*this);
- }
-
- Compound &Compound::operator+=(const Compound &r)
- // Adds r to this number. Stores the result in this number.
- {
- return operator=(*this + r);
- }
-
- Compound &Compound::operator-=(const Compound &r)
- // Subtracts r from this number. Stores the result in
- // this number.
- {
- return operator=(*this - r);
- }
-
- Compound &Compound::operator*=(const Compound &r)
- // Mutliplies this number by r. Stores the result in
- // this number.
- {
- return operator=(*this * r);
- }
-
- Compound &Compound::operator/=(const Compound &r)
- // Divides this number by r. Stores the result in
- // this number.
- {
- return operator=(*this / r);
- }
-
- Compound &Compound::operator++()
- // Prefix increment operator. Safe to use
- // in expressions like ++(++r).
- {
- return *this += 1;
- }
-
- Compound &Compound::operator--()
- // Prefix decrement operator. Safe to use
- // in expressions like --(--r).
- {
- return *this -= 1;
- }
-
- Compound Compound::operator++(int)
- // Postfix increment. Note that we don't return a reference
- // as we do with prefix increment. Instead a copy of the result
- // is returned. Thus, expressions like (c++)++ will not return
- // the correct result.
- // WARNING: Result not checked for possible overflow.
- {
- Compound old(*this);
- *this += 1;
- return old;
- }
-
- Compound Compound::operator--(int)
- // Postfix decrement. Note that we don't return a reference
- // as we do with prefix decrement. Instead a copy of the result
- // is returned. Thus, expressions like (c--)-- will not return
- // the correct result.
- // WARNING: Result not checked for possible overflow.
- {
- Compound old(*this);
- *this -= 1;
- return old;
- }
-
- Compound operator+(const Compound &a, const Compound &b)
- // Adds a and b, returning the result. Uses the formula:
- // a + b = (aw + af) + (bw + bf) = (aw + bw) + (af + bf)
- // and simplifies the result.
- {
- return Compound(a.w + b.w, a.f + b.f);
- }
-
- Compound operator-(const Compound &a, const Compound &b)
- // Subtracts b from a and returns result. Uses the
- // operator+() function to do the dirty work.
- // WARNING: Result not checked for possible overflow.
- {
- Compound nb(b);
- nb.Negate();
- return a + nb; // Ie: a + (-b)
- }
-
- Compound operator*(const Compound &a, const Compound &b)
- // Multiplies a and b together, returning the result.
- // Uses the formula: a * b = (aw + af) * (bw + bf)
- // = aw*bw + af*bf + aw*bf + af*bw
- // In the calculations, we keep extracting the whole part
- // of the fraction terms, to keep down chances of overflow.
- {
- long rw = a.w * b.w;
- Rational rf(a.f * b.f);
- rw += rf.RemoveWholePart();
- rf += a.w * b.f;
- rw += rf.RemoveWholePart();
- rf += a.f * b.w;
- rw += rf.RemoveWholePart();
- return Compound(rw, rf);
- }
-
- Compound operator/(const Compound &a, const Compound &b)
- // Divides a by b, returning the result. Note that
- // operator*() does all the dirty work.
- // WARNING: On divide by zero, an "undefined" result is
- // returned, but no other forms of overflow are checked.
- {
- Compound ib(b);
- ib.Invert(); // Might become undefined
- return a * ib; // Ie: a * (1/b)
- }
-
- int operator==(const Compound &a, const Compound &b)
- // ASSUMES a & b are simplified.
- {
- return a.w == b.w && a.f == b.f;
- }
-
- int operator!=(const Compound &a, const Compound &b)
- // Inequality operator.
- {
- return !(a == b);
- }
-
- int operator<(const Compound &a, const Compound &b)
- // Returns 1 if a < b, else 0. Note that if either
- // a and/or b is undefined, the result is 0.
- // ASSUMES a & b are simplified.
- {
- if (a.w > b.w) return 0;
- if (a.w < b.w) return 1;
- // At this point, a.w == b.w
- return a.f < b.f;
- }
-
- int operator<=(const Compound &a, const Compound &b)
- // Note: Using !(operator>(a,b)) would not work for
- // all cases. (Eg: if a and/or b are undefined.)
- {
- return a == b || a < b;
- }
-
- int operator>(const Compound &a, const Compound &b)
- // Returns 1 if a > b, else 0. Note that if either
- // a and/or b is undefined, the result is 0.
- // ASSUME a & b are simplified.
- {
- if (a.w < b.w) return 0;
- if (a.w > b.w) return 1;
- // At this point, a.w == b.w
- return a.f > b.f;
- }
-
- int operator>=(const Compound &a, const Compound &b)
- // Note: Using !(operator<(a,b)) would not work for
- // all cases. (Eg: if a and/or b are undefined.)
- {
- return a == b || a > b;
- }
-